using System;
using System.Collections.Generic;
using SharpObjects.Configuration;
using SharpObjects.Configuration.ConfigurationProviders;
using SharpObjects.Interfaces;

namespace SharpObjects.Logging.LogTargets
{
    public abstract class LogTargetBase : IXmlInitializable, IDisposable, ILogTarget 
	{
		protected System.Threading.Mutex mutex = null;
        protected IOriginFilter originFilter = null;
        protected bool isEnabled = true;
        protected ILogFormatter formatter = null;
        protected const string formatterTag = "formatter";
        protected const string formatter_id_tag = "formatter_id";
        protected int maxSize = 1024 * 1024;

	    protected LogTargetBase()
		{
		}

		protected void CreateMutex(string name)
		{
			if(this.mutex != null)
			{
				this.mutex.Close();
			}

			// create this.mutex for thread safety
			this.mutex = new System.Threading.Mutex(false, name);

			if(this.mutex == null)
			{
				throw new Exception("Could not create an object of System.Threading.Mutex");
			}
		}

        public string Id { get; set; }

        #region IXmlInitializable Members

        public virtual void Initialize(System.Xml.XmlElement initializationElement)
        {
            IConfigurationProvider init = new XmlConfigurationProvider(initializationElement);

            this.Id = init.GetString("@id", initializationElement.Name);

            if (initializationElement.HasAttribute("is_enabled"))
            {
                this.isEnabled = init.GetBoolean("@is_enabled");
            }
            else
            {
                this.isEnabled = init.GetBoolean("is_enabled", true);
            }

            this.originFilter = init.GetObject<IOriginFilter>("origin_filter", new OriginFilter());
            InitializeSize(init);

            this.IsInitialized = true;
        }

        public bool IsInitialized { get; set; }


        #endregion

        protected void InitializeSize(IConfigurationProvider init)
        {
            this.maxSize = init.GetInteger("log_max_size", this.maxSize);
            string sizeUnits = init.GetString("log_max_size/@units", "b").ToLower();

            switch (sizeUnits)
            {
                case "kb":
                    this.maxSize *= 1024;
                    break;
                case "mb":
                    this.maxSize *= 1024 * 1024;
                    break;
                case "gb":
                    this.maxSize *= 1024 * 1024 * 1024;
                    break;
                default:
                    break;
            }
        }
        //#region IDisposable Members

        protected abstract void Close();

        public void Dispose()
        {
            Close();
        }

        //#endregion


        #region ILogTarget Members


        public ILogFormatter Formatter { get { return this.formatter; } set { this.formatter = value; } }


        public virtual void Write(ILogEntry logEntry)
        {
            if (this.isEnabled)
            {
                if (this.originFilter != null && this.originFilter.Pass(logEntry.Origin))
                {
                    this.mutex.WaitOne(TimeSpan.FromSeconds(10));

                    try
                    {
                        WriteToLog(logEntry);
                    }
                    catch (Exception exception)
                    {
                        Log.AddErrorMessage(exception);
                    }

                    this.mutex.ReleaseMutex();
                }
            }
        }

        protected abstract void WriteToLog(ILogEntry logEntry);

        public abstract void Release();

        #endregion
    }
}
